#pragma once
#include "timer.h"
#include "sheduler.h"
#include <sys/epoll.h>
#include <fcntl.h>
#include <cassert>

namespace sylar{

class IOManager:public TimerManager , public Sheduler
{   
public:
    enum Event{
        NONE = 0x0,
        READ = 0x1,
        WRTIE = 0X4 
    };
private:
    //每个fd都有的一个fdcontext
    struct FdContext{
        int _sockfd;
        Event _events;
        struct EventContext  //每个事件上下文
        {
            func_t _func; //回调函数
            std::shared_ptr<Fiber> _fiber; //协程
            Sheduler* _sheduler; //关联的调度器
        };
        EventContext readContext;
        EventContext writeContext;
        std::mutex _mtx;
        EventContext& getEventContext(Event event); //通过事件获取上下文
        void resetEventContext(EventContext& evc); //重置事件上下文
        void triggerEvent(Event event); //触发事件
    };
private:
    int _epoll_fd;
    std::shared_mutex _smtx; //读写锁
    std::vector<FdContext*> _FdContextV;//
    int _tickleFds[2];//用于线程间通信的管道文件描述符，fd[0] 是读端，fd[1] 是写端。
    std::atomic<size_t> _pendingEventCount = {0}; //记录等待处理的事件数量

public:
    //threads线程数量，use_caller是否讲主线程或调度线程包含进行，name调度器的名字
    IOManager(size_t threads = 1, bool use_caller = true, const std::string &name = "IOManager");//允许设置线程数量、是否使用调用者线程以及名称。
    ~IOManager();
    //事件管理方法
    // add one event at a time
    int addEvent(int fd, Event event, std::function<void()> cb = nullptr);//添加一个事件到文件描述符 fd 上，并关联一个回调函数 cb。
    // delete event
    bool delEvent(int fd, Event event);//删除文件描述符fd上的某个事件
    // delete the event and trigger its callback
    bool cancelEvent(int fd, Event event);//取消文件描述符上的某个事件，并触发其回调函数
    // delete all events and trigger its callback
    bool cancelAll(int fd);//取消文件描述符 fd 上的所有事件，并触发所有回调函数。

    static IOManager* GetThis(); //获取当前线程的iomanager
protected:
    //通知调度器有任务调度
    //其实现方式是往内部管道（m_tickleFds）的写端（fd[1]）写入数据，以此唤醒处于epoll_wait阻塞状态的 idle 协程（空闲协程）。
   //idle 协程被唤醒后会主动让出 CPU（yield），此时调度器的Scheduler::run方法就能从任务队列中取出新任务进行调度执行，确保新任务及时被处理。
    void tickle() override;
	//判断调度器是否可以停止
    //判断条件是Scheduler::stopping()外加IOManager的m_pendingEventCount为0，表示没有IO事件可调度
    bool can_stop() override;

    void idle() override;//这里也是scheduler的重写，当调度器中没有其他待执行的任务时，idle 协程会进入运行状态，阻塞等待 IO 事件的发生。

    void onTimerInsertAtFront() override;//因为Timer类的成员函数重写当有新的定时器插入到前面时的处理逻辑

    void contextResize(size_t size);//调整文件描述符上下文数组的大小。
};    


}
